#include "xmlview.h" 
#include "system.h"
#include "resource.h"
#include "winassert.h"
#include <commdlg.h>

using std::runtime_error;
using win::Window;
using win::ChildWindow;
using win::Rect;
using win::Tree;
using win::TreeViewItem;
using win::Point;
using win::Menu;

namespace  view {
	using std::vector;
	using view::TuxTree;
	using doc::DocNode;
	using doc::Structure;
	using doc::pointer_list;
	using doc::StructurePtrList;
	
	const int IDX_TREE = 1;

	LRESULT CALLBACK TuxTree::WndProc(HWND hwnd, UINT msg,
 								  WPARAM wParam, LPARAM lParam)
	{
		try
		{
		static Window w;
		static TuxTree* tree = 0;
		w.Attach(hwnd);
		switch (msg)
		{
			case WM_NOTIFY:
				{
					const int id = (int) wParam;
					if (id == IDX_TREE)
					{
						const NM_TREEVIEW & hdr = *((LPNM_TREEVIEW) lParam);
					    tree = static_cast <TuxTree *> (w.GetPointer());
						if (hdr.hdr.code == TVN_SELCHANGED)
							tree->OnSelChanged(reinterpret_cast<DocNode*> (hdr.itemNew.lParam),
                                               hdr.itemOld.hItem);
						return 0;
      				}
				}
			case WM_CONTEXTMENU:
				{
				    tree = static_cast <TuxTree *> (w.GetPointer());
     				tree->OnContextMenu(LOWORD(lParam),HIWORD(lParam));
			        return 0;
				}
			case WM_DESTROY:
				{
				    tree = static_cast <TuxTree *> (w.GetPointer());
				    tree->OnDestroy();
				    return 0;
				}
	    	case WM_COMMAND:
	    		{
	    			const int id = LOWORD(wParam);
				    tree = static_cast <TuxTree *> (w.GetPointer());
		    		switch (id)
		    		{
		    			case  IDM_COPY:
		    				tree->OnCopy();
		    				break;
		    			case  IDM_CUT:
		    				tree->OnCut();
		    				break;
		    			case  IDM_PASTE:
		    				tree->OnPaste();
		    				break;
		    			case  IDM_MOVE_UP:
		    			case  IDM_MOVE_DOWN:
		    			case  IDM_MOVE_TOP:
		    			case  IDM_MOVE_BOTTOM:
		    				tree->OnMove(id);
		    				break;
		    			case  IDM_CONTEXT_DELETE:
		    				tree->OnDelete();
		    				break;
		    			default:
		    				if (id <= IDM_CONTEXT_ADD_ITEM_LAST &&
		    					id >= IDM_CONTEXT_ADD_ITEM_FIRST)
		    					{
		    						tree->OnContextMenuAdd(id);
				    				return 0;
				    			}
		    		}
    			}
		}
		}
		catch (exception &e)
		{
			::MessageBox(0,e.what(),"Error from TuxTree::WndProc",MB_OK);
		}
		return  DefWindowProc( hwnd,msg,wParam,lParam );
	}
	


	void TuxTree::Create(const Window &parent,
	                         const int child_index)
	{
	     _child_index = child_index;
	     const HWND parent_handle = parent.GetHandle();
	     const HINSTANCE instance_handle = reinterpret_cast<HINSTANCE>
	         					(GetWindowLong(parent_handle,GWL_HINSTANCE));
		 // Register editor window
		 static const char * TREE_CLASS = "xml_tree";

		 WNDCLASS wc;
		 ZeroMemory(&wc,sizeof(wc));
		 wc.style = WS_OVERLAPPED;
		 wc.hInstance = instance_handle;
		 wc.hbrBackground = NULL;
//		 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
		 wc.lpfnWndProc = TuxTree::WndProc;
		 wc.lpszClassName = TREE_CLASS;
		 if (!RegisterClass(&wc))
		 	throw runtime_error("Register class failed");

	 	_hwnd = CreateWindow( TREE_CLASS,NULL,
	  							WS_CHILD | WS_VISIBLE | WS_BORDER ,
	  							0,0,0,0,
	         					parent_handle,
	         					reinterpret_cast<HMENU> (_child_index),
	  							instance_handle,
	  							NULL);
		if (_hwnd == NULL)
			throw runtime_error("Create window failed");
	  	SetPointer(this);

  		// Tree control
		_tree.Create(*this,IDX_TREE);

		
		TuxDocument::Instance().Attach(this);
	}


	void TuxTree::OnMove(Rect r)
	{
		Move(r);
		r.MoveTo(0,0);
	 	_tree.Move(r);
	}
	
	void TuxTree::AppendNode(TreeItem &t, DocNode * n)
	{
		ASSERT(n != 0);
		TreeViewItem i;
		string name;
		n->GetNameLabel(name);
		i.SetText(name.c_str());
		i.SetData(n);
		TreeItem p;
		if (!t.IsNull())
 			p = t.Append(i);
 		else
 		{
 			_tree.SetRoot(i);
 			p = _tree.GetRoot();
 		}
 		AppendChildNodes(p,n);
	}
	
	void TuxTree::AppendChildNodes(TreeItem &p, DocNode * n)
	{
    	pointer_list<DocNode>::const_iterator it = n->Childs().begin();
    	while (it != n->Childs().end())
    	{
    		AppendNode(p,*it);
			it++;
    	}
	}

	void TuxTree::ReloadTree()
	{
		_tree.DeleteAllItems();
		if (TuxDocument::Instance().IsValid())
		{
			TreeItem null;
			AppendNode(null,TuxDocument::Instance().GetRootNode());
		}
	}
	
	void TuxTree::ReloadFocusNode()
	{
  		TreeItem focus = _tree.GetFocusItem();
  		focus.DeleteChilds();
		AppendChildNodes(focus,TuxDocument::Instance().FocusNode());
		focus.Expand();
	}
	
	void TuxTree::OnDestroy()
	{
	}
	
	void TuxTree::ShowFocusNode()
	{
		TreeItem item;
  		if (_oldItem == 0)
  		{
			item = _tree.GetFocusItem();
			if (item.IsNull())
				return;
		}
  		else
  			item = _tree.GetTreeItem(_oldItem);

		if (!TuxDocument::Instance().IsNodeSelected())
			return;
					
		TreeViewItem tvi;
		item.GetView(tvi);
		string name;
		TuxDocument::Instance().FocusNode()->GetNameLabel(name);
  		tvi.SetText(name.c_str());
  		item.SetView(tvi);
	}
	
	void TuxTree::Update(Observable *s, int aspect)
	{
			switch (aspect)
			{
				case TuxDocument::ASPECT_FILE:
					ReloadTree();
					break;
				case TuxDocument::ASPECT_FOCUS_NAME_UPDATE:
					ShowFocusNode();
					break;
			}
	}
	
	void TuxTree::BuildContextMenu()
	{
			// reconstruct items in the context menu
			_contextMenu.RemoveAllMenus();
			TuxDocument & doc = TuxDocument::Instance();

			
			// The Add menu item			
      		pointer_list<const Structure> adds;
      		ASSERT(doc.FocusNode());
      		doc.FocusNode()->GetAddableStructures(adds);
			if (adds.size() != 0)
			{
				PopupMenu menu;								
	   			unsigned int pos = 0;
	      		pointer_list<const Structure>::iterator it = adds.begin();
	      		while (it != adds.end())
	      		{
					menu.AppendItem(IDM_CONTEXT_ADD_ITEM_FIRST + pos, 
     							(*it)->Name().c_str(),
     							(void *) (*it));
	      			it++;
	      			pos++;
	      		}
	      		if (pos == 0)
	      			menu.Destroy();
      			else
      			{
      			   _contextMenu.AppendItem(IDM_CONTEXT_ADD,"Add");
      			   _contextMenu.SetItemSubMenu(IDM_CONTEXT_ADD,menu);
   			    }
			}      		
			
			// The move menu
			PopupMenu menuMove;
			if (doc.FocusNode()->CanMove(DocNode::mmTop))
				menuMove.AppendItem(IDM_MOVE_TOP,"To Top");
			if (doc.FocusNode()->CanMove(DocNode::mmUp))
				menuMove.AppendItem(IDM_MOVE_UP,"Up");
			if (doc.FocusNode()->CanMove(DocNode::mmDown))
				menuMove.AppendItem(IDM_MOVE_DOWN,"Down");
			if (doc.FocusNode()->CanMove(DocNode::mmBottom))
				menuMove.AppendItem(IDM_MOVE_BOTTOM,"To Bottom");
			if (menuMove.Count() == 0)
				menuMove.Destroy();
			else 
   			{
				_contextMenu.AppendItem(IDM_CONTEXT_MOVE,"Move");
    			_contextMenu.SetItemSubMenu(IDM_CONTEXT_MOVE,menuMove);
			}
				
			if (_contextMenu.Count() > 0)
				_contextMenu.AppendSeperator();
			_contextMenu.AppendItem(IDM_CUT,"Cut");
			_contextMenu.AppendItem(IDM_COPY,"Copy");
			_contextMenu.AppendItem(IDM_PASTE,"Paste");
			if (doc.FocusNode()->CanDelete())
				_contextMenu.AppendItem(IDM_CONTEXT_DELETE,"Delete");
			
	}
	
	void TuxTree::OnContextMenu(int x, int y)
	{
		try
		{

			// select the item
			Point p(x,y);
   			ScreenToClient(p);
   			HTREEITEM at = _tree.ItemAt(p);
   			if (at != 0)
   			{
	   			_tree.Select(at);
			}
			// set dynamic items that might have changed since build
			TuxDocument & doc = TuxDocument::Instance();
			const bool canCut = doc.IsNodeSelected() && doc.FocusNode()->CanDelete();
			const bool canPaste = doc.IsNodeSelected() && doc.CanCloneToFocus();
			_contextMenu.EnableMenuItemById(IDM_CUT,canCut);
			_contextMenu.EnableMenuItemById(IDM_PASTE,canPaste);
        	// position and show the menu
			_contextMenu.Track(x,y,_hwnd);
		}
  		catch (exception &e)
  		{
  			::MessageBox(NULL,e.what(),"error",MB_OK);
  		}
	}
	
	void TuxTree::OnSelChanged(DocNode * pNode, HTREEITEM item)
	{	
  		ASSERT(TuxDocument::Instance().GetRootNode());
  		_oldItem = item;
		TuxDocument::Instance().SetFocusNode(pNode);
		_oldItem = 0;
		BuildContextMenu();
	}
	
	void TuxTree::OnContextMenuAdd(unsigned int menuId)
	{
		void * data = _contextMenu.GetItemData(menuId);
		ASSERT(data);
		const Structure * s =
  				reinterpret_cast<Structure *> (data);
  				
  		// add to document and to tree
    	DocNode * n = TuxDocument::Instance().NewFocusNodeChild(*s);
    	TreeItem focus = _tree.GetFocusItem();
    	AppendNode(focus,n);
    	focus.Expand();
    	focus.SelectChildByData(n);
	}

	void TuxTree::OnDelete()
	{
		ASSERT(TuxDocument::Instance().IsNodeSelected());
		TuxDocument::Instance().DeleteFocusNode();
    	TreeItem oldFocus = _tree.GetFocusItem();
    	TreeItem newFocus = oldFocus.Parent();
    	newFocus.DeleteItem(oldFocus);
    	newFocus.Select();
	}

	void TuxTree::OnCut()
	{
		TuxDocument &doc = TuxDocument::Instance();
		ASSERT(doc.IsNodeSelected());
		if (doc.HasCutCloneSource())
		{
			if (!AskBox("Cutting now destroys the previously cut item "
                        "in the local clipboard.\n"
                        "Are you sure you want to continue?"))
				return;
		}
		doc.CutFocus();
    	TreeItem oldFocus = _tree.GetFocusItem();
    	TreeItem newFocus = oldFocus.Parent();
    	newFocus.DeleteItem(oldFocus);
    	newFocus.Select();
	}

	void TuxTree::OnCopy()
	{	
		TuxDocument &doc = TuxDocument::Instance();
		ASSERT(doc.IsNodeSelected());
		if (doc.HasCutCloneSource())
		{
			if (!AskBox("Copying now destroys the previously cut item "
                        "in the local clipboard.\n"
                        "Are you sure you want to continue?"))
				return;
		}
		doc.CopyFocus();
	}
	
	void TuxTree::OnPaste()
	{
		ASSERT(TuxDocument::Instance().IsNodeSelected());
		TuxDocument::Instance().CloneToFocus();
		ReloadFocusNode();
	}
	
	void TuxTree::MoveSelected(const DocNode::eMoveMethod mm)
	{
		ASSERT(TuxDocument::Instance().IsNodeSelected());
		DocNode* focusNode = TuxDocument::Instance().FocusNode();
		focusNode->Move(mm);
		LockWindowUpdate(_hwnd);
    	TreeItem parent = _tree.GetFocusItem().Parent();
  		parent.DeleteChilds();
		AppendChildNodes(parent,TuxDocument::Instance().FocusNode());
		const bool result = parent.SelectChildByData(focusNode);
		LockWindowUpdate(NULL);
		ASSERT(result);
	}

	void TuxTree::OnMove(const int id)
	{
		switch (id)
		{
			case  IDM_MOVE_UP:
				MoveSelected(DocNode::mmUp);
				break;
   			case  IDM_MOVE_DOWN:
				MoveSelected(DocNode::mmDown);
   				break;
   			case  IDM_MOVE_TOP:
				MoveSelected(DocNode::mmTop);
   				break;
   			case  IDM_MOVE_BOTTOM:
				MoveSelected(DocNode::mmBottom);
   				break;
		}
	}

}


namespace {
}

namespace view
{
	using std::runtime_error;
	using sys::exception;
	using win::Window;
	using win::ChildWindow;
	using win::Splitter;
	using win::Toolbar;
	using win::Rect;
	using win::PopupMenu;
	using win::Menu;
	using doc::string_basket;

	const int IDX_SPLIT_HOR = 5;
	const int IDX_SPLIT_VERT = 6;
	const int IDX_TOOLBAR = 7;
	const short PART_SELECTED = 0;
	const short PART_HINT = 1;
	const char * TXT_NONE_SELECTED = "No item selected";
	const char * TXT_NONE_SELECTED_HINT = "Select an item in the tree";
	const char * TXT_FILE_FILTER = "Xml Files (*.xml)\0*.xml\0Tuxpad Files (*.tux)\0*.tux\0\0";

	XmlView xmlview;

	LRESULT CALLBACK XmlView::WndProc (HWND hwnd, UINT message, WPARAM wParam,
 										LPARAM lParam)
	{
	    switch (message)                  /* handle the messages */
	    {
	    	case WM_NOTIFY:
	    		xmlview.OnNotify(wParam,((LPNMHDR) lParam)->code);
	    		break;
	    	case WM_COMMAND:
	    		switch (LOWORD(wParam))
	    		{
	    			case IDM_EXIT:
	    				::SendMessage(hwnd,WM_CLOSE,0,0);
	    				break;
	    			case IDM_FILE_OPEN:
	    				xmlview.OnFileOpen();
	    				break;
	    			case IDM_FILE_OPEN_TEMPLATE:
	    				xmlview.OnFileOpenTemplate();
	    				break;
	    			case IDM_VIEW_RESTORE_LAYOUT:
	    				xmlview.OnRestoreLayout();
	    				break;
					case IDM_FILE_SAVEANDPREVIEW:
						xmlview.OnFileSaveAndPreview();
						break;
	    			case IDM_FILE_SAVE:
	    				xmlview.OnFileSave();
	    				break;
	    			case IDM_SET_FONT:
        				xmlview.OnSetFont();
            			break;	           			
	    			/* TODO (#3#): Rationalise these events -- maybe a notify method on 
	    			               the tuxtree control? */
	    			case IDM_CUT:
	    				xmlview._tree.OnCut();
	    				break;
	    			case IDM_COPY:
	    				xmlview._tree.OnCopy();
	    				break;
	    			case IDM_PASTE:
	    				xmlview._tree.OnPaste();
	    				break;
	    			case IDM_MOVE_UP:
	    				xmlview.OnNodeMove(DocNode::mmUp);
	    				break;
        			case IDM_MOVE_DOWN:
	    				xmlview.OnNodeMove(DocNode::mmDown);
            			break;	
	    			case IDM_MOVE_TOP:
	    				xmlview.OnNodeMove(DocNode::mmTop);
	    				break;
        			case IDM_MOVE_BOTTOM:
	    				xmlview.OnNodeMove(DocNode::mmBottom);
            			break;	
	    			default:
	    				if (LOWORD(wParam) >= IDM_FILE_NEW_FIRST &&
	    					LOWORD(wParam) <= IDM_FILE_NEW_LAST)
	    			    {
	    			    	xmlview.OnFileNew(LOWORD(wParam) - IDM_FILE_NEW_FIRST);
	            			break;
	                    }

		            	return DefWindowProc (hwnd, message, wParam, lParam);
	    		}
	    		break;
	    	case WM_SIZE:
	    		xmlview.OnSize(LOWORD(lParam),HIWORD(lParam));
	   		//	return DefWindowProc (hwnd, message, wParam, lParam);
	    		break;
	  		case WM_CREATE:
				xmlview.OnCreate(hwnd);
				break;
	        case WM_CLOSE:
   				if (xmlview.OnFileClose())	
		        {
          			PostQuitMessage (0);
          		}
   				break;
	        default:                      /* for messages that we don't deal with */
	            return DefWindowProc (hwnd, message, wParam, lParam);
	    }

	    return 0;
	}


	XmlView::XmlView()
	: _editor(),
	 _tree(), _split_vert(_tree,Splitter::right),
	 _capture(), _split_hor(_capture,Splitter::bottom)
	{
		TuxDocument::Instance().Prefs.YSplit = 0;
		_textFont = NULL;
	}

	XmlView::~XmlView()
	{
		if (_textFont != NULL)
		{
			DeleteObject(_textFont);
		}
		
	}


	
	void XmlView::OnFileSave()
	{
		try
		{
			if (TuxDocument::Instance().HasFileName())
				TuxDocument::Instance().SaveToFile();
			else
				OnFileSaveAs(); /// get the file name
		} 		
		catch (exception &e)
		{
	  		MessageBox(e.what(),"Error");
	 	}
	}

	void XmlView::OnFileSaveAndPreview()
	{
		try
		{
			OnFileSave();
			TuxDocument &doc = TuxDocument::Instance();
			if (doc.HasFileName())
			{
				STARTUPINFO si;
				PROCESS_INFORMATION pi;

				ZeroMemory( &si, sizeof(si) );
				si.cb = sizeof(si);
				si.wShowWindow = SW_HIDE;
				si.dwFlags = STARTF_USESHOWWINDOW;
				ZeroMemory( &pi, sizeof(pi) );

				const char * format = "cmd /Q /C \"%s%\"";
				const char * filename = doc.FileName().c_str();
				const size_t BUFFER_LEN = strlen(format) + strlen(filename);
				char * command = new char[BUFFER_LEN+1];
				sprintf_s(command,BUFFER_LEN,format,filename);

				// Start the child process. 
				if( !CreateProcess( NULL,   // No module name (use command line). 
					command, // Command line. 
					NULL,             // Process handle not inheritable. 
					NULL,             // Thread handle not inheritable. 
					FALSE,            // Set handle inheritance to FALSE. 
					0,                // No creation flags. 
					NULL,             // Use parent's environment block. 
					NULL,             // Use parent's starting directory. 
					&si,              // Pointer to STARTUPINFO structure.
					&pi )             // Pointer to PROCESS_INFORMATION structure.
					) 
				{
					delete[] command;
					throw sys::system_error(filename,GetLastError());
				}
				delete[] command;
			}
		} 		
		catch (exception &e)
		{
	  		MessageBox(e.what(),"Error");
	 	}
	}


	void XmlView::OnSetFont()
	{
		try
		{
			LOGFONT font;
			TuxDocument::Instance().Prefs.GetTextFont(font);
			CHOOSEFONT cf;
			ZeroMemory(&cf,sizeof(cf));
			cf.lStructSize = sizeof(cf);
			cf.hwndOwner = _hwnd;
			cf.lpLogFont = &font;
			cf.Flags = CF_TTONLY | CF_FORCEFONTEXIST | CF_NOSIMULATIONS	
   					| CF_SCREENFONTS | CF_NOSCRIPTSEL | CF_INITTOLOGFONTSTRUCT;
   			if (ChooseFont(&cf))
      		{
				if (_textFont != NULL)
				{
					DeleteObject(_textFont);
					_textFont = NULL;
				}
				_textFont = CreateFontIndirect(&font);
				_editor.SetBoxFont(_textFont);
				TuxDocument::Instance().Prefs.SetTextFont(font);
           	}		
		} 		
		catch (exception &e)
		{
	  		MessageBox(e.what(),"Error");
	 	}
	}
	
	void XmlView::OnFileSaveAs()
	{
		try
		{
		   	OPENFILENAME ofn;
			char file_name[MAX_PATH+1];
		   	ZeroMemory(&ofn, sizeof(ofn));
			strcpy_s(file_name,MAX_PATH, TuxDocument::Instance().FileName().c_str());
		   	ofn.lStructSize = sizeof(ofn);
		   	ofn.hwndOwner = _hwnd;
		   	ofn.lpstrFilter = TXT_FILE_FILTER;
		   	ofn.lpstrFile = file_name;
		   	ofn.nMaxFile = MAX_PATH;
		   	ofn.lpstrDefExt = ".xml";

		   	ofn.Flags =  OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT;
			if (TuxDocument::Instance().docTemplate().IsTemplate())
			{
				string newname = TuxDocument::Instance().Prefs.TemplatePath() + "untitled.xml";
				strcpy_s(file_name,MAX_PATH, newname.c_str());
      		}
		  	if(GetSaveFileName(&ofn))
		  	{
		  		TuxDocument::Instance().SaveToFile(file_name);
		  		ShowFileName();
		   	}

	    }
		catch (exception &e)
		{
	  		MessageBox(e.what(),"Error");
	 	}
	}
	
	void XmlView::OnFileOpen()
	{
		try
		{
			if (!OnFileClose())
				return;
		   	OPENFILENAME ofn;
			char file_name[MAX_PATH+1];
		   	ZeroMemory(&ofn, sizeof(ofn));
		   	file_name[0] = 0;

		   	ofn.lStructSize = sizeof(ofn);
		   	ofn.hwndOwner = _hwnd;
		   	ofn.lpstrFilter = TXT_FILE_FILTER;
		   	ofn.lpstrFile = file_name;
		   	ofn.nMaxFile = MAX_PATH;
		   	ofn.lpstrDefExt = "xml";
		   	ofn.Flags = OFN_FILEMUSTEXIST |
      					OFN_HIDEREADONLY | OFN_NOREADONLYRETURN;
		  	if(GetOpenFileName(&ofn))
		  	{
		     	TuxDocument::Instance().CloseDocument();
		  		TuxDocument::Instance().LoadFromFile(file_name);
		   	} 
	    }
		catch (exception &e)
		{
	  		MessageBox(e.what(),"Error");
	 	}
	}

	void XmlView::OnFileOpenTemplate()
	{
		try
		{
			if (!OnFileClose())
				return;
		   	OPENFILENAME ofn;
			char file_name[MAX_PATH+1];
		   	ZeroMemory(&ofn, sizeof(ofn));
		   	file_name[0] = 0;

		   	ofn.lStructSize = sizeof(ofn);
		   	ofn.hwndOwner = _hwnd;
		   	ofn.lpstrFilter = TXT_FILE_FILTER;
		   	ofn.lpstrInitialDir = TuxDocument::Instance().Prefs.TemplatePath().c_str();
		   	ofn.lpstrFile = file_name;
		   	ofn.nMaxFile = MAX_PATH;
		   	ofn.lpstrDefExt = "xml";
		   	ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR |
      					OFN_HIDEREADONLY | OFN_NOREADONLYRETURN;
		  	if(GetOpenFileName(&ofn))
		  	{
		     	TuxDocument::Instance().CloseDocument();
		  		TuxDocument::Instance().LoadFromFile(file_name);
		   	} 
	    }
		catch (exception &e)
		{
	  		MessageBox(e.what(),"Error");
	 	}
	}


	void XmlView::OnCreate(const HWND hwnd)
	{
		try
		{
			TuxDocument::Instance().Attach(this);
			TuxDocument::Instance().Prefs.Load();
			 Attach(hwnd);
			_editor.Create(*this,1);
			_capture.Create(*this,2);
			_tree.Create(*this,3);

   			win::int_array w;
   			w.push_back(200);
   			w.push_back(-1);
			_status.Create(*this,4);
			_status.SetParts(w);
			_status.SetPartText(PART_SELECTED,TXT_NONE_SELECTED);
			_status.SetPartText(PART_HINT,TXT_NONE_SELECTED_HINT);

			_split_vert.Create(*this,IDX_SPLIT_VERT);
			_split_hor.Create(*this,IDX_SPLIT_HOR);

			_toolbar.Create(*this,IDX_TOOLBAR);
			_toolbar.AddWindowsButton(Toolbar::file_open,IDM_FILE_OPEN,true);
			_toolbar.AddWindowsButton(Toolbar::file_save,IDM_FILE_SAVE,false);
			_toolbar.AddSeperator();
			_toolbar.AddWindowsButton(Toolbar::edit_cut,IDM_CUT,false);
			_toolbar.AddWindowsButton(Toolbar::edit_copy,IDM_COPY,false);
			_toolbar.AddWindowsButton(Toolbar::edit_paste,IDM_PASTE,false);
			_toolbar.AddSeperator();
			vector<int> ids;
			ids.push_back(IDM_MOVE_TOP);
			ids.push_back(IDM_MOVE_UP);
			ids.push_back(IDM_MOVE_DOWN);
			ids.push_back(IDM_MOVE_BOTTOM);
			_toolbar.AddResourceButtons(BMP_TOOLBAR,ids);
			_toolbar.SetButtonState(IDM_MOVE_UP,false);
			_toolbar.SetButtonState(IDM_MOVE_DOWN,false);
			_toolbar.SetButtonState(IDM_MOVE_TOP,false);
			_toolbar.SetButtonState(IDM_MOVE_BOTTOM,false);
   			_toolbar.ShowWindow();

			// Add File|New menu items
			PopupMenu menu;
			const string_basket& structures =TuxDocument::Instance().Prefs.GetTemplates();
			string_basket::const_iterator it = structures.begin();
			int index = 0;
			while (it != structures.end())
			{
			  menu.AppendItem(IDM_FILE_NEW_FIRST+index, it->c_str());
			  it++;
			  index++;
			}
			Menu main(_hwnd);
			main.SetItemSubMenu(IDM_FILE_NEW,menu);
			
			// Set fonts
			_capture.SetBoxFont(_tree.GetTreeFont());			
		}
		catch (exception &e)
		{
			::MessageBox(0,e.what(),"Error on Create",MB_OK);
		}
	}

	void XmlView::OnPaint()
	{

	}

	void XmlView::OnNodeMove(const DocNode::eMoveMethod mm)
	{
		_tree.MoveSelected(mm);
	}
	
	void XmlView::OnFileNew(int templateIndex)
	{
		try
		{
			if (OnFileClose())
			{
			   	TuxDocument::Instance().CloseDocument();
				TuxDocument::Instance().NewFromTemplate(templateIndex);
			}
		}
		catch (exception &e)
		{
			::MessageBox(0,e.what(),"Error on Parsing Template", MB_OK);
		}
		catch (...)
		{
			::MessageBox(0,"Unknown Error","Error on Parsing Template", MB_OK);
		}
	}

	void XmlView::OnSize(const int x, const int y)
	{
		const int x_split = TuxDocument::Instance().Prefs.XSplit==0?x >> 1:TuxDocument::Instance().Prefs.XSplit;
		const int x_center = x_split + _split_vert.Thickness;
		const int h_size = x - x_center;

		const int top = _toolbar.GetHeight();
		const int bottom = y - _status.GetHeight();
		const int y_split = TuxDocument::Instance().Prefs.YSplit==0?(bottom-top) >> 1:(TuxDocument::Instance().Prefs.YSplit-top);
		const int y_center = y_split + _split_hor.Thickness + top;
		const int v_size = bottom - y_center;
		LockWindowUpdate(_hwnd);
		_tree.OnMove(Rect(0,top,x_split,bottom-top,true));
		_capture.AdjustLayout(x_center,top,h_size,y_split);
		_editor.AdjustLayout(x_center,y_center,h_size,v_size);
		_status.AdjustLayout();
		_split_vert.AdjustLayout();
		_split_hor.AdjustLayout();
	 	_toolbar.AdjustLayout();
		LockWindowUpdate(NULL);
  }

	void XmlView::OnNotify(const int id, const UINT code)
	{
		if (id == IDX_SPLIT_VERT)
		{
			if (TuxDocument::Instance().Prefs.XSplit == code) return;
	 	    RECT r;
			GetClientRect(r);
			const int splitPos = code;
			if (splitPos < r.right - _split_hor.Thickness)
				TuxDocument::Instance().Prefs.XSplit = splitPos;
			else
				return;
			OnSize(r.right,r.bottom);
			UpdateWindow();
		}
		else if (id == IDX_SPLIT_HOR)
		{
			if (TuxDocument::Instance().Prefs.YSplit == code) return;
	 	    RECT r;
			GetClientRect(r);
			const int splitPos = code;
			if (splitPos < r.bottom	- _split_vert.Thickness	- _status.GetHeight()
				&& splitPos > _toolbar.GetHeight())
				TuxDocument::Instance().Prefs.YSplit = splitPos;
			else
				return;
			OnSize(r.right,r.bottom);
			UpdateWindow();
		}

	}

	void XmlView::OnRestoreLayout()
	{
	 	TuxDocument::Instance().Prefs.XSplit = TuxDocument::Instance().Prefs.YSplit = 0;
	    RECT r;
		GetClientRect(r);
		OnSize(r.right,r.bottom);
	 	UpdateWindow();
	}
	
	void XmlView::ShowFileName()
	{
		const TuxDocument& doc = TuxDocument::Instance();
		const char * dirtyMark = doc.IsDirty()?"*]":"]";
		string header = doc.docTemplate().name()
  			 				+ " [" 
          					+ doc.FileName() 
               				+ dirtyMark;
		SetText(header.c_str());
	}
	
	void XmlView::SetCanSave(const bool value)
	{
  		// Enable save button and menu
  		/* TODO (#1#): This features is disabled until messaging is improved */
  		if (value==false) return;
  		_toolbar.SetButtonState(IDM_FILE_SAVE,value);
  		Menu menu(GetHandle());
  		menu.EnableMenuItemById(IDM_FILE_SAVE,value);  // File|Save
  		menu.EnableMenuItemById(IDM_FILE_SAVEANDPREVIEW,value);  // File|Save
	}

	void XmlView::Update(Observable*,int aspect)
	{
		TuxDocument &doc = TuxDocument::Instance();
		static bool font_set = false;
		switch (aspect)
		{
			case TuxDocument::ASPECT_FILE:
				if (!font_set)
				{
					LOGFONT font;
					TuxDocument::Instance().Prefs.GetTextFont(font);
					if (*font.lfFaceName != '\0')
					{
						_textFont = CreateFontIndirect(&font);
						ASSERT(_textFont != NULL);
		    			_editor.SetBoxFont(_textFont);
					}
					font_set = true;
				}
				ShowFileName();
				SetCanSave(TuxDocument::Instance().IsDirty());
				_status.SetPartText(PART_SELECTED,TXT_NONE_SELECTED);
				_status.SetPartText(PART_HINT,TXT_NONE_SELECTED_HINT);
				break;
			case TuxDocument::ASPECT_FOCUS_OPEN:
				if (doc.IsNodeSelected())
				{
					string label;
					const DocNode& node = *(doc.FocusNode());
					node.GetLabel(label);
					_status.SetPartText(PART_SELECTED,label.c_str());
					_status.SetPartText(PART_HINT,node.NodeStructure().Hint().c_str());
					const bool canup = node.CanMove(DocNode::mmUp);
					const bool candown = node.CanMove(DocNode::mmDown);
					_toolbar.SetButtonState(IDM_MOVE_UP,canup);
					_toolbar.SetButtonState(IDM_MOVE_DOWN,candown);
					_toolbar.SetButtonState(IDM_MOVE_TOP,canup);	
					_toolbar.SetButtonState(IDM_MOVE_BOTTOM,candown);
					_toolbar.SetButtonState(IDM_COPY,true);
					_toolbar.SetButtonState(IDM_CUT,doc.FocusNode()->CanDelete());
					_toolbar.SetButtonState(IDM_PASTE,doc.CanCloneToFocus());
				}
				else
				{
					_toolbar.SetButtonState(IDM_MOVE_UP,false);
					_toolbar.SetButtonState(IDM_MOVE_DOWN,false);
					_toolbar.SetButtonState(IDM_COPY,false);
					_toolbar.SetButtonState(IDM_CUT,false);
					_toolbar.SetButtonState(IDM_PASTE,false);
					_status.SetPartText(PART_SELECTED,TXT_NONE_SELECTED);
					_status.SetPartText(PART_HINT,TXT_NONE_SELECTED_HINT);
 				}
 				break;
			case TuxDocument::ASPECT_DIRTY_UPDATE:
				ShowFileName();
				SetCanSave(TuxDocument::Instance().IsDirty());
				break;
			case TuxDocument::ASPECT_CLONE_UPDATE:
				ASSERT(doc.IsNodeSelected());
				_toolbar.SetButtonState(IDM_CUT,doc.FocusNode()->CanDelete());
				_toolbar.SetButtonState(IDM_PASTE,doc.CanCloneToFocus());
				break;
   				
				
   		}
	}

	// returns true if ok to close file
	bool XmlView::OnFileClose()
	{
		TuxDocument::Instance().PrepareForClose();
  		TuxDocument::Instance().Prefs.Save();
  		if (TuxDocument::Instance().IsDirty())
     	{
     		const int answer =
		     		::MessageBox(_hwnd,"Do you want to save the current file?",
     							"Confirm", MB_YESNOCANCEL | MB_ICONQUESTION);
     		if (answer == IDYES)
    			OnFileSave();
			else if (answer == IDCANCEL)
				return false;
     	}
     	return true;
	}


}
